﻿using System;
using System.Collections.Generic;
using System.Timers;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Miris.HumanMilkAnalyser.DataModel;
using Miris.HumanMilkAnalyser.Service.Shared;
using Miris.HumanMilkAnalyser.WPF.Model;
using Miris.HumanMilkAnalyser.WPF.Shared;

namespace Miris.HumanMilkAnalyser.WPF.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class MainViewModel : MyViewModelBase
    {
        public const string ReturnHomeMessageToken = "MainViewModeReturnHomeMessage";
        public const string GoToGetAnalysisResultPageMessageToken = "MainViewModelGoToGetAnalysisResultPageMessage";
        public const string GoToCreatePatientPageMessageToken = "MainViewModelGoToCreatePatientPageMessage";
        public const string GoToPatientDataSearchPageMessageToken = "MainViewModelGoToPatientDataSearchPageMessage";
        public const string GoToDiagnosticMessageReferenceSetupPageMessageToken = "MainViewModelGoToDiagnosticMessageReferenceSetupPageMessage";
        public const string GoToDataManagementPageMessageToken = "MainViewModelGoToDataManagementPageMessage";
        public const string GoToFurtherSuggestionPageMessageToken = "MainViewModelGoToFurtherSuggestionPageMessage";
        public const string GoToBasicConfigurationPageMessageToken = "MainViewModelGoToBasicConfigurationPageMessage";
        public const string GoToHelpPageMessageToken = "MainViewModelGoToHelpPageMessage";
        public const string GoToRegistrationCodePageMessageToken = "MainViewModelGoToRegistrationCodePageMessage";

        private enum DayOfWeekChinese
        {
            星期日 = 0,
            星期一 = 1,
            星期二 = 2,
            星期三 = 3,
            星期四 = 4,
            星期五 = 5,
            星期六 = 6
        }

        private Timer _timer;

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel(IDataService dataService)
            : base(dataService)
        {
            try
            {
                StartTimerToDisplaySystemDateTime();
                LoadSharedAnalysisItemList();
            }
            catch (Exception ex)
            {
                RequestDisplayErrorMessage(ex.Message);
            }
        }

        /// <summary>
        /// Register all necessary messages. It is called by constructor in base class.
        /// </summary>
        protected override void RegisterMessages()
        {
            base.RegisterMessages();

            Messenger.Default.Register<string>(this, MyViewModelBase.RequestDisplayErrorMessageToken, (msg) =>
            {
                SetupErrorMessage(msg);
            });

            Messenger.Default.Register<string>(this, MyViewModelBase.RequestClearErrorMessageToken, (msg) =>
            {
                ClearErrorMessage();
            });

            Messenger.Default.Register<string>(this, MyViewModelBase.RequestDisplayMessageToken, (msg) =>
            {
                SetupSummaryrMessage(msg);
            });

            Messenger.Default.Register<string>(this, MyViewModelBase.RequestClearMessageToken, (msg) =>
            {
                ClearSummaryrMessage();
            });
        }

        /// <summary>
        /// The <see cref="ErrorMessage" /> property's name.
        /// </summary>
        public const string ErrorMessagePropertyName = "ErrorMessage";

        private string _errorMessage = string.Empty;

        /// <summary>
        /// Sets and gets the ErrorMessage property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string ErrorMessage
        {
            get
            {
                return _errorMessage;
            }

            set
            {
                if (_errorMessage == value)
                {
                    return;
                }

                RaisePropertyChanging(ErrorMessagePropertyName);
                _errorMessage = value;
                RaisePropertyChanged(ErrorMessagePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="ErrorMessageVisibility" /> property's name.
        /// </summary>
        public const string ErrorMessageVisibilityPropertyName = "ErrorMessageVisibility";

        private Visibility _errorMessageVisibility = Visibility.Collapsed;

        /// <summary>
        /// Sets and gets the ErrorMessageVisibility property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public Visibility ErrorMessageVisibility
        {
            get
            {
                return _errorMessageVisibility;
            }

            set
            {
                if (_errorMessageVisibility == value)
                {
                    return;
                }

                RaisePropertyChanging(ErrorMessageVisibilityPropertyName);
                _errorMessageVisibility = value;
                RaisePropertyChanged(ErrorMessageVisibilityPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SummaryMessage" /> property's name.
        /// </summary>
        public const string SummaryMessagePropertyName = "SummaryMessage";

        private string _summaryMessage = string.Empty;

        /// <summary>
        /// Sets and gets the SummaryMessage property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string SummaryMessage
        {
            get
            {
                return _summaryMessage;
            }

            set
            {
                if (_summaryMessage == value)
                {
                    return;
                }

                RaisePropertyChanging(SummaryMessagePropertyName);
                _summaryMessage = value;
                RaisePropertyChanged(SummaryMessagePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SummaryMessageVisibility" /> property's name.
        /// </summary>
        public const string SummaryMessageVisibilityPropertyName = "SummaryMessageVisibility";

        private Visibility _summaryMessageVisibility = Visibility.Collapsed;

        /// <summary>
        /// Sets and gets the SummaryMessageVisibility property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public Visibility SummaryMessageVisibility
        {
            get
            {
                return _summaryMessageVisibility;
            }

            set
            {
                if (_summaryMessageVisibility == value)
                {
                    return;
                }

                RaisePropertyChanging(SummaryMessageVisibilityPropertyName);
                _summaryMessageVisibility = value;
                RaisePropertyChanged(SummaryMessageVisibilityPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CurrentSystemDateTime" /> property's name.
        /// </summary>
        public const string CurrentSystemDateTimePropertyName = "CurrentSystemDateTime";

        private string _currentSystemDateTime;

        /// <summary>
        /// Sets and gets the CurrentSystemDateTime property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public string CurrentSystemDateTime
        {
            get
            {
                return _currentSystemDateTime;
            }

            set
            {
                if (_currentSystemDateTime == value)
                {
                    return;
                }

                RaisePropertyChanging(CurrentSystemDateTimePropertyName);
                _currentSystemDateTime = value;
                RaisePropertyChanged(CurrentSystemDateTimePropertyName);
            }
        }

        private RelayCommand _getAnalysisResultCommand;

        /// <summary>
        /// Gets the GetAnalysisResultCommand.
        /// </summary>
        public RelayCommand GetAnalysisResultCommand
        {
            get
            {
                return _getAnalysisResultCommand
                    ?? (_getAnalysisResultCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send ReturnHomeMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, ReturnHomeMessageToken);
                                          }));
            }
        }

        private RelayCommand _createPatientCommand;

        /// <summary>
        /// Gets the CreatePatientCommand.
        /// </summary>
        public RelayCommand CreatePatientCommand
        {
            get
            {
                return _createPatientCommand
                    ?? (_createPatientCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToCreatePatientPageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToCreatePatientPageMessageToken);
                                          }));
            }
        }

        private RelayCommand _patientDataSearchCommand;

        /// <summary>
        /// Gets the PatientDataSearchCommand.
        /// </summary>
        public RelayCommand PatientDataSearchCommand
        {
            get
            {
                return _patientDataSearchCommand
                    ?? (_patientDataSearchCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToPatientDataSearchPageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToPatientDataSearchPageMessageToken);
                                          }));
            }
        }

        private RelayCommand _diagnosticMessageReferenceSetupCommand;

        /// <summary>
        /// Gets the DiagnosticMessageReferenceSetupCommand.
        /// </summary>
        public RelayCommand DiagnosticMessageReferenceSetupCommand
        {
            get
            {
                return _diagnosticMessageReferenceSetupCommand
                    ?? (_diagnosticMessageReferenceSetupCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToDiagnosticMessageSetupPageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToDiagnosticMessageReferenceSetupPageMessageToken);
                                          }));
            }
        }

        private RelayCommand _furtherSuggestionCommand;

        /// <summary>
        /// Gets the FurtherSuggestionCommand.
        /// </summary>
        public RelayCommand FurtherSuggestionCommand
        {
            get
            {
                return _furtherSuggestionCommand
                    ?? (_furtherSuggestionCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToFurtherSuggestionPageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToFurtherSuggestionPageMessageToken);
                                          }));
            }
        }

        private RelayCommand _dataManagementCommand;

        /// <summary>
        /// Gets the DataManagementCommand.
        /// </summary>
        public RelayCommand DataManagementCommand
        {
            get
            {
                return _dataManagementCommand
                    ?? (_dataManagementCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToDataManagementPageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToDataManagementPageMessageToken);
                                          }));
            }
        }

        private RelayCommand _basicConfigurationCommand;

        /// <summary>
        /// Gets the BasicConfigurationCommand.
        /// </summary>
        public RelayCommand BasicConfigurationCommand
        {
            get
            {
                return _basicConfigurationCommand
                    ?? (_basicConfigurationCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToBasicConfigurationPageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToBasicConfigurationPageMessageToken);
                                          }));
            }
        }

        private RelayCommand _helpCommand;

        /// <summary>
        /// Gets the HelpCommand.
        /// </summary>
        public RelayCommand HelpCommand
        {
            get
            {
                return _helpCommand
                    ?? (_helpCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToHelpPageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToHelpPageMessageToken);
                                          }));
            }
        }

        private RelayCommand _registrationCodeCommand;

        /// <summary>
        /// Gets the RegistrationCodeCommand.
        /// </summary>
        public RelayCommand RegistrationCodeCommand
        {
            get
            {
                return _registrationCodeCommand
                    ?? (_registrationCodeCommand = new RelayCommand(
                                          () =>
                                          {
                                              // Send GoToRegistrationCodePageMessage to PageBase.
                                              // Use Command stead of Click event because of the Storyboard trigger.
                                              Messenger.Default.Send<int>(0, GoToRegistrationCodePageMessageToken);
                                          }));
            }
        }

        /// <summary>
        /// Setup the ErrorMessage.
        /// </summary>
        /// <param name="msg">The string of error message.</param>
        private void SetupErrorMessage(string msg)
        {
            if (!ErrorMessage.Contains(msg))
            {
                ErrorMessage += msg + ";";
            }

            ErrorMessageVisibility = string.IsNullOrEmpty(msg) ? Visibility.Collapsed : Visibility.Visible;
        }

        /// <summary>
        /// Setup the ErrorMessage.
        /// </summary>
        private void ClearErrorMessage()
        {
            ErrorMessage = string.Empty;
            ErrorMessageVisibility = Visibility.Collapsed;
        }

        /// <summary>
        /// Setup the SummaryrMessage.
        /// </summary>
        /// <param name="msg">The string of summary message.</param>
        private void SetupSummaryrMessage(string msg)
        {
            if (!SummaryMessage.Contains(msg))
            {
                SummaryMessage += msg + ";";
            }

            SummaryMessageVisibility = string.IsNullOrEmpty(msg) ? Visibility.Collapsed : Visibility.Visible;
        }

        /// <summary>
        /// Clear the SummaryrMessage.
        /// </summary>
        private void ClearSummaryrMessage()
        {
            SummaryMessage = string.Empty;
            SummaryMessageVisibility = Visibility.Collapsed;
        }

        /// <summary>
        /// Load all AnalysisItem that stored in SharedVariableStorage.
        /// </summary>
        private void LoadSharedAnalysisItemList()
        {
            SharedEntityStorage.LoadSharedAnalysisItemList(ServiceFactory);
        }

        /// <summary>
        /// Start the timer to display current system date time.
        /// </summary>
        private void StartTimerToDisplaySystemDateTime()
        {
            CurrentSystemDateTime = "获取中 ...";
            _timer = new Timer(1000);
            _timer.Elapsed += Timer_Elapsed;
            _timer.Start();
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            var currentDateTime = DateTime.Now;

            CurrentSystemDateTime = string.Format("{0} {1}",
                currentDateTime.ToString(GeneralUtility.LongDateTimeFormat),
                (DayOfWeekChinese)currentDateTime.DayOfWeek);
        }
    }
}